Add SN/I certificate support over mTLS Proof-of-Possession (PoP)#1040
Draft
Robbie-Microsoft wants to merge 1 commit into
Draft
Add SN/I certificate support over mTLS Proof-of-Possession (PoP)#1040Robbie-Microsoft wants to merge 1 commit into
Robbie-Microsoft wants to merge 1 commit into
Conversation
Allow a confidential-client app configured with a Subject-Name/Issuer (SN/I) certificate to obtain an mTLS-bound PoP access token from Entra ID by presenting that same certificate as the client TLS certificate in the mutual-TLS handshake to the token endpoint, instead of signing a private_key_jwt (x5c) client assertion.
Opt in via ClientCredentialParameters.builder(...).mtlsProofOfPossession(). Adds TokenType, BindingCertificate, MtlsClientCertificateHelper, and MtlsEndpointHelper; threads the mTLS socket factory through the HTTP layer; derives the mtlsauth.* endpoint (region optional); builds the mtls_pop request (direct cert -> no assertion; FIC Leg 2 -> jwt-pop with mtlsBindingCertificate); parses token_type and surfaces the public binding certificate; and isolates the cache on {token_type + cert KeyId}. Also covers the 2-leg FIC over mTLS PoP where both legs are cert-bound.
The existing SNI+Bearer (assertion) and broker SHR-PoP flows are unchanged. Includes unit tests, an E2E integration test (MtlsPopIT), a sample, and docs/changelog updates.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for using a Subject-Name/Issuer (SN/I) certificate as the first-leg credential over mTLS Proof-of-Possession (PoP).
Today an SN/I cert is used to sign a
private_key_jwt(x5c) client assertion, which yields a Bearer token (SNI + Bearer — unchanged). This PR lets a confidential-client app present that same certificate as the client TLS certificate in the mutual-TLS handshake to the token endpoint, so Entra ID (ESTS) returns a token that is cryptographically bound to the cert (token_type=mtls_pop,cnf/x5t#S256). The credential is identical; only the mechanism changes (assertion-signer → TLS client cert).Also covers the 2-leg Federated Identity Credential (FIC) over mTLS PoP, where both legs are cert-bound and the final token is bound to the Leg-1 certificate thumbprint.
Public API
ClientCredentialParameters.Builder.mtlsProofOfPossession()ConfidentialClientApplication.Builder.mtlsBindingCertificate(IClientCertificate)TokenType(BEARER/MTLS_POP),BindingCertificate(public material only), plusAuthenticationResultMetadata.tokenType()/bindingCertificate().Internal changes
TokenType,BindingCertificate,MtlsClientCertificateHelper(mTLS socket factory, thumbprint, binding-cert resolution),MtlsEndpointHelper(login.*→mtlsauth.*host rewrite; region optional → globalmtlsauth.microsoft.com; tenanted-authority validation; sovereign-cloud fail-fast).TokenRequestExecutor): direct cert path omitsclient_assertion; FIC Leg 2 sendsclient_assertion_type=...:jwt-pop; result populatestokenType/bindingCertificate.OAuthHttpRequest/HttpHelper/IHttpHelpervia an injected mTLSDefaultHttpClient(MSAL owns the mTLS transport).{token_type + cert KeyId}so Bearer and PoP (and different certs) never alias.TokenType.telemetryValue()(BEARER=2, MTLS_POP=6) for cross-SDK parity; the locked v5 wire header is intentionally left unchanged.Backward compatibility
The existing SNI + Bearer (assertion) and broker SHR-PoP flows are unchanged and remain byte-for-byte identical — validated by the full existing unit suite.
Testing
MtlsEndpointHelperTest,MtlsClientCertificateHelperTest,MtlsProofOfPossessionTest) + a hermetic PKCS12 resource. Full suite: 410 tests, 0 failures, 0 errors, 0 skipped.MtlsPopIT— direct SNI→PoP (global + regional), Bearer/PoP cache isolation, and 2-leg FIC (both legs bound). CI-only: requires the lab SN/I cert (non-CNG) + an ESTS allow-listed resource; ESTS gates mTLS PoP on the final resource audience.Docs / samples
confidential-client/ClientCredentialMtlsProofOfPossession.javachangelog.txtand.github/copilot-instructions.mdupdatedOut of scope / follow-ups
user_fic) FIC over mTLS PoP.Risks / open questions